#pragma once

#include <atomic>
#include <cassert>
#include <mutex>


namespace MemoryPool
{
#define MEMORY_POOL_SIZE 64
#define SLOT_BASE_SIZE 8
#define MAX_SLOT_SIZE 512

struct Slot
{
    std::atomic<Slot*> next;// 原子指针
};

class MemoryPool
{
private:
    int                       _blockSize;    //内存块的大小（默认4096）
    int                       _slotSize;     //每一个槽的大小
    Slot*                     _firstBlock;   //指向内存池管理的第一个内存块（里面可以用来存储下一块内存池的第一个内存块位置）
    Slot*                     _curSlot;      //指向当前未被使用过的槽
    std::atomic<Slot*>        _freeList;     //当前空闲的槽（被使用过后又被释放的，没有申请的不算）
    Slot*                     _lastSlot;     //作为当前内存块中最后能够存放元素的位置标识(超过该位置需申请新的内存块)
    std::mutex                _mutexForBlock;// 保证多线程情况下避免不必要的重复开辟内存导致的浪费行为

public:
    MemoryPool(size_t blockSize = 4096);
    ~MemoryPool();

    void init(size_t);

    void *allocate();
    void deallocate(void *);

private:
    void allocateNewBlock();
    size_t padPointer(char* p, size_t align);

    //使用CAS操作进行无锁入队和出队
    bool pushFreeList(Slot* slot);
    Slot* popFreeList();
};

class HashBucket
{
public:
    static void InitMemoryPool();
    static MemoryPool& getMemoryPool(int index);

    static void* useMemory(size_t size)
    {
        if (size <= 0)
        {
            return nullptr;
        }
        if (size > MAX_SLOT_SIZE)
        {
            return operator new(size);
        }
        return getMemoryPool(((size+7)/SLOT_BASE_SIZE)-1).allocate();
    }

    static void freeMemory(void* ptr,size_t size)
    {
        if (!ptr)
        {
            return;
        }
        if (size > MAX_SLOT_SIZE)
        {
            operator delete(ptr);
            return ;
        }
        getMemoryPool(((size + 7) / SLOT_BASE_SIZE) - 1).deallocate(ptr);
    }

    template<typename T, typename... Args>
    friend T* newElement(Args&&... args);

    template<typename T>
    friend void deleteElement(T* p);
};

template<typename T,typename ... Args>
T* newElement(Args&& ... args)
{
    T* p = nullptr;
    // 根据元素大小选取合适的内存池分配内存
    if ((p = reinterpret_cast<T*>(HashBucket::useMemory(sizeof(T)))) != nullptr)
    {
        // 在分配的内存上构造对象
        new(p) T(std::forward<Args>(args)...);
    }
    return p;
}

template<typename T>
void deleteElement(T* p)
{
    if (p)
    {
        p->~T();
        // 内存回收
        HashBucket::freeMemory(reinterpret_cast<void*>(p), sizeof(T));
    }
}

}
